#include <slothttpd/config/configuration.hpp>
#include <slothttpd/config/server.hpp>
#include <slothttpd/connection.hpp>
#include <slothttpd/http/status.hpp>
#include <slothttpd/config/location/base_location.hpp>
#include <slothttpd/logger.hpp>

#include <boost/property_tree/json_parser.hpp>
#include <boost/make_shared.hpp>

namespace slothttpd {
namespace config {

configuration_ptr configuration::instance;

configuration::configuration(const boost::property_tree::ptree &root)
{
    log_file                = root.get<std::string>("log_file", "/dev/null");
    
    bound_address           = root.get("bound_address", "0.0.0.0");
    port                    = root.get<unsigned>("port", 80);
    workers                 = root.get<unsigned>("workers", 1);
    pool_size               = root.get<std::size_t>("pool_size", 512);
    receive_buffers.size    = root.get<std::size_t>("receive_buffers.size", 1024);
    receive_buffers.nmax    = root.get<std::size_t>("receive_buffers.nmax", 1024);
    max_content_length      = root.get<std::size_t>("max_content_length", 1024 * 1024);
    
    auto it = root.find("fcgi_apps");
    if (it != root.not_found()) {
        for (auto &v : it->second) {
            fcgi_apps.push_back(boost::make_shared<fcgi_app>(v.second, *this));
        }
    }
    
    for (auto &v : root.get_child("servers")) {
        servers.push_back(boost::make_shared<config::server>(v.second, *this));
    }
}

void configuration::handle_uri(connection_ptr c)
{
    //logger() << c->request << std::endl;
    
    server_ptr dest_host;
    
    for (auto &serv : servers) {
        if (serv->match_host(c->request.host)) {
            dest_host = serv;
            break;
        }
    }
    
    if (!servers.empty() && dest_host.get() == nullptr) {
        dest_host = servers.front();
    }
    
    if (dest_host.get() != nullptr) {
        for (auto &loc : dest_host->locations) {
            if (loc->match_path(c->request.path)) {
                loc->apply(c);
                return;
            }
        }
    }
    
    c->send_stock_response(http::status::not_found);
}

configuration_ptr configuration::from_file(const std::string &filename)
{
    boost::property_tree::ptree root;
    
    boost::property_tree::json_parser::read_json(filename, root);
    
    return boost::make_shared<configuration>(root);
}

std::ostream &operator<<(std::ostream &os, const configuration::buffer_list &b)
{
    return os << "{ size: " << b.size << ", nmax: " << b.nmax << " }";
}

std::ostream &operator<<(std::ostream &os, const configuration &c)
{
    os << "log_file          : " << c.log_file << '\n';
    
    os << "bound_address     : " << c.bound_address << '\n';
    os << "port              : " << c.port << '\n';
    os << "workers           : " << c.workers << '\n';
    os << "pool_size         : " << c.pool_size << '\n';
    os << "receive_buffers   : " << c.pool_size << '\n';
    os << "pool_size         : { size: " << c.receive_buffers.size << ", nmax: " << c.receive_buffers.nmax << " }\n";
    os << "max_content_length: " << c.max_content_length << '\n';
    
    for (auto &ptr : c.servers) {
        os << (*ptr);
    }
    
    for (auto &ptr : c.fcgi_apps) {
        os << (*ptr);
    }
    
    return os;
}

}
}
